package com.v.air.app.ui;

import com.ftdi.j2xx.D2xxManager;
import com.ftdi.j2xx.FT_Device;
import com.v.air.app.tools.PreferencesTool;

import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;

public class B3UARTConnector extends Thread {
	public interface DataListener {
		public void OnDataUpdate(float pm25, float co2, float tvoc,
				float temperature, float humidity);
	}

	D2xxManager ftdid2xx;
	FT_Device ftDev = null;
	Context mUARTContext = null;
	DataListener mDelegate = null;
	Handler mMessageHandler = null;
	boolean mbTreadLoop = false;

	public B3UARTConnector(Context context, DataListener delegate) {
		this(context, delegate, null);
	}

	public B3UARTConnector(Context context, DataListener delegate,
			Handler messageHandler) {
		mUARTContext = context;
		mDelegate = delegate;
		mMessageHandler = messageHandler;
		this.setPriority(Thread.NORM_PRIORITY);
		try {
			ftdid2xx = D2xxManager.getInstance(context);
			ftdid2xx.setVIDPID(0x0403, 0xada1);
		} catch (D2xxManager.D2xxException ex) {
			ex.printStackTrace();
		}
	}

	public boolean startDetection() {

		if (ftdid2xx.createDeviceInfoList(mUARTContext) > 0) {
			ftDev = ftdid2xx.openByIndex(mUARTContext, 0);
			if (ftDev != null) {
				ftDev.setBitMode((byte) 0, D2xxManager.FT_BITMODE_RESET);
				ftDev.setBaudRate(9600);
				ftDev.setDataCharacteristics((byte) 8, (byte) 1, (byte) 0);
				ftDev.setFlowControl((byte) 0, (byte) 0x0b, (byte) 0x0d);

				mbTreadLoop = true;
				this.start();
				return true;
			}
		}
		mbTreadLoop = false;
		this.start();
		return false;
	}

	public void stopDetection() {
		mbTreadLoop = false;
		try {
			Thread.sleep(200);
			this.interrupt();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		if (ftDev != null) {
			synchronized (ftDev) {
				if (true == ftDev.isOpen()) {
					ftDev.close();
					ftDev = null;
				}
			}
		}
	}

	private void _sleep(int num) {
		int i = 0;
		for (i = 0; i < num && mbTreadLoop; i += 10) {
			try {
				Thread.sleep(10);
			} catch (InterruptedException e) {
			}
		}
	}

	private boolean readBytes(FT_Device dev, byte[] buffRet, int length) {
		int len = 0, delayCount = 0;
		byte[] buf = new byte[512];
		while (len < length && delayCount < 200 && mbTreadLoop) {
			delayCount += 10;
			_sleep(10);
			int dsize = ftDev.getQueueStatus();
			if (dsize > 0) {
				dev.read(buf, dsize);
				for (int i = 0; i < dsize; i++) {
					buffRet[len + i] = buf[i];
				}
				len += dsize;
			}
		}
		return len == length;
	}

	@Override
	public void run() {
		byte[] byteBuffer = new byte[512];

		int cmd_idx = -1;
		byte[] cmd_pm25 = new byte[] { 0x00, 0x03, 0x00, 0x00, 0x00, 0x01,
				(byte) 0x85, (byte) 0xDB };
		byte[] cmd_co2 = new byte[] { 0x00, 0x03, 0x00, 0x03, 0x00, 0x01,
				(byte) 0x75, (byte) 0xDB };
		byte[] cmd_tvoc = new byte[] { 0x00, 0x03, 0x00, 0x04, 0x00, 0x01,
				(byte) 0xC4, (byte) 0x1A };
		byte[] cmd_tem_hum = new byte[] { 0x00, 0x03, 0x00, 0x01, 0x00, 0x02,
				(byte) 0x94, (byte) 0x1A };

		float _pm25 = 0, _co2 = 0, _tvoc = 0, _temperature = 0, _humidity = 0;
		int readedParams = 0;

		while (mbTreadLoop) {
			FT_Device dev = ftDev;
			if (dev != null) {
				int len = dev.getQueueStatus();
				if (len > 0) {
					byte[] buf = new byte[len + 1];
					dev.read(buf, len);
				}
				synchronized (dev) {
					cmd_idx = (cmd_idx + 1) % 5;
					switch (cmd_idx) {
					case 0:
						ftDev.write(cmd_pm25, cmd_pm25.length);
						if (readBytes(dev, byteBuffer, 7)) {
							int byte3=((int)byteBuffer[3])&0xFF;
							int byte4=((int)byteBuffer[4])&0xFF;							
							_pm25 = byte3 * 256 + byte4;
							++readedParams;
						}
						break;
					case 1:
						ftDev.write(cmd_co2, cmd_co2.length);
						if (readBytes(dev, byteBuffer, 7)) {
							int byte3=((int)byteBuffer[3])&0xFF;
							int byte4=((int)byteBuffer[4])&0xFF;							
							_co2 = byte3 * 256 + byte4;
							++readedParams;
						}
						break;
					case 2:
						ftDev.write(cmd_tvoc, cmd_tvoc.length);
						if (readBytes(dev, byteBuffer, 7)) {
							int byte3=((int)byteBuffer[3])&0xFF;
							int byte4=((int)byteBuffer[4])&0xFF;							
							_tvoc = byte4 + ((float) byte3) / 100;
							++readedParams;
						}
						break;
					case 3:
						ftDev.write(cmd_tem_hum, cmd_tem_hum.length);
						if (readBytes(dev, byteBuffer, 9)) {
							int byte3=((int)byteBuffer[3])&0xFF;
							int byte4=((int)byteBuffer[4])&0xFF;							
							int byte5=((int)byteBuffer[5])&0xFF;
							int byte6=((int)byteBuffer[6])&0xFF;							

							_temperature = (int) (byte4 & 0x7F)
									+ ((float) byte3) / 10;
							if ((byte4 & 0x80) > 0) {
								_temperature = -_temperature;
							}
							_humidity = (int) (byte6)
									+ ((float) byte5) / 10;
							++readedParams;
						}
						break;
					case 4:
						if (readedParams == 4) {
							String text = "PM2.5 = " + String.valueOf(_pm25)
									+ "\nCO2 = " + String.valueOf(_co2)
									+ "\nTVOC = " + String.valueOf(_tvoc)
									+ "\ntemperature = "
									+ String.valueOf(_temperature)
									+ "\nhumidity = "
									+ String.valueOf(_humidity);
							toast(text);
							PreferencesTool.putFloat(mUARTContext, "pm", _pm25);
							PreferencesTool.putFloat(mUARTContext, "co2", _co2);
							PreferencesTool.putFloat(mUARTContext, "tvoc", _tvoc);
							PreferencesTool.putFloat(mUARTContext, "temperature", _temperature);
							PreferencesTool.putFloat(mUARTContext, "humidity", _humidity);
//							mDelegate.OnDataUpdate(_pm25, _co2, _tvoc,
//									_temperature, _humidity);
						}
						_sleep(1000);
						readedParams = 0;
						break;
					}
				}
			}
			try {
				Thread.sleep(50);
			} catch (InterruptedException e) {
			}
		}
		stopDetection();
	}

	void toast(String text) {
		if (mMessageHandler != null) {
			Message msg = new Message();
			Bundle data = new Bundle();
			data.putString("text", text);
			msg.what = 100;
			msg.setData(data);
			mMessageHandler.sendMessage(msg);
		}
	}

}
